/**
 * DoublyLinkedList All purpose data structure is a queue, stack, and linkedlist
 * also provides cycling of a current Object in list Author: Kyle Van Wie
 * Version v1 v1 Initial Version
 */
public class DoublyLinkedList<E> {
	Node<E> last;
	Node<E> first;
	int current;
	int size;

	public DoublyLinkedList() {
		last = null;
		first = null;
		current = 0;
		size = 0;
	}

	public void addBack(E Obj) {
		if (size == 0) {
			last = new Node<E>(Obj);
			last.setNext(last);
			last.setPrev(last);
			first = last;

		} else {
			Node<E> temp = new Node<E>(Obj);
			temp.setPrev(last);
			last.setNext(temp);
			last = temp;
			last.setNext(first);
		}
		size++;
	}

	public void addFront(E Obj) {
		if (size == 0) {

			first = new Node<E>(Obj);
			first.setNext(first);
			first.setPrev(first);
			last = first;
		} else {
			Node<E> temp = new Node<E>(Obj);
			temp.setNext(first);
			first.setPrev(temp);
			first = temp;
			first.setPrev(last);
		}
		size++;
	}

	public void addIndex(E Obj, int Index) {
		if (Index == 0) {
			addFront(Obj);
		} else if (Index == size) {
			addBack(Obj);
		} else if (Index > 1 && Index < size) {
			Node<E> temp = first;
			for (int i = 0; i < Index; i++) {
				temp = temp.getNext();
			}
			Node<E> freshNode = new Node<E>(Obj);
			freshNode.setNext(temp);
			freshNode.setPrev(temp.getPrev());
			temp.getPrev().setNext(freshNode);
			temp.setPrev(freshNode);
			size++;

		}
	}

	public E removeFirst() {
		E element = null;
		if (size == 1) {
			element = first.getElement();
			first = null;
			last = null;
			current = 0;
			size--;
		} else if (size != 0 && size != 1) {
			element = first.getElement();
			first.getPrev().setNext(first.getNext());
			first.getNext().setPrev(first.getPrev());
			first = first.getNext();
			size--;
		}
		return element;
	}

	public E removeLast() {
		E element = null;

		if (size == 1) {
			element = last.getElement();
			first = null;
			last = null;
			current = 0;
			size--;
		} else if (size != 0 && size != 1) {
			element = last.getElement();
			last.getPrev().setNext(last.getNext());
			last.getNext().setPrev(last.getPrev());
			last = last.getPrev();
			size--;
		}
		return element;
	}

	public E removeCurrent() {
		E element = null;
		if (size > 0) {
			element = removeIndex(current);
		}
		return element;
	}

	public E removeIndex(int Index) {

		E element = null;
		if (Index == 0) {
			element = removeFirst();
		} else if (Index == size - 1) {
			element = removeLast();
		} else if (Index > -1 && Index < size) {
			Node<E> temp = first;
			if (size == 1) {
				element = last.getElement();
				last = null;
				first = null;
				current = 0;
				size--;
			} else if (size > 1) {
				for (int i = 0; i < Index; i++) {
					temp = temp.getNext();
				}
				element = temp.getElement();
				temp.getPrev().setNext(temp.getNext());
				temp.getNext().setPrev(temp.getPrev());
				size--;
			}
		}
		return element;
	}

	public int getSize() {
		return size;
	}

	public boolean isEmpty() {
		if (size == 0) {
			return true;
		}
		return false;
	}

	public E peekLast() {
		E element = null;
		if (size != 0) {
			element = last.getElement();
		}
		return element;
	}

	public E peekFirst() {
		E element = null;
		if (size != 0) {
			element = first.getElement();
		}
		return element;
	}

	public E peekIndex(int Index) {
		E element = null;
		if (Index == 0) {
			element = peekFirst();
		} else if (Index == size - 1) {
			element = peekLast();
		} else if (size != 0 && Index > -1 && Index < size - 1) {
			Node<E> temp = first;
			for (int i = 0; i < Index; i++) {
				temp = temp.getNext();
			}
			element = temp.getElement();
		}
		return element;
	}

	public E peekCurrent() {
		return peekIndex(current);
	}

	public void next() {
		if (current == size - 1)
			current = 0;
		else
			current++;

		return;
	}

	public void prev() {
		if (current == 0)
			current = size - 1;
		else
			current--;
		return;
	}

	public void setCurrent(int Index) {
		current = Index;
		return;
	}

	public static void main(String args[]) {
		DoublyLinkedList<String> DLL = new DoublyLinkedList<String>();
		// DLL.addBack("1");
		// DLL.addBack("2");
		// DLL.addBack("3");
		// DLL.addBack("4");
		// DLL.addBack("5");
		// DLL.addBack("6");
		// DLL.addBack("7");
		// DLL.addBack("8");
		// DLL.addBack("9");
		// DLL.addBack("10");
		// DLL.addFront("1");
		// DLL.addFront("2");
		// DLL.addFront("3");
		// DLL.addFront("4");
		// DLL.addFront("5");
		// DLL.addFront("6");
		// DLL.addFront("7");
		// DLL.addFront("8");
		// DLL.addFront("9");
		// DLL.addFront("10");
		// DLL.addIndex("1", 0);
		// DLL.addIndex("2", 1);
		// DLL.addIndex("3", 2);
		// DLL.addIndex("4", 3);
		// DLL.addIndex("5", 4);
		// DLL.addIndex("6", 4);
		// DLL.addIndex("7", 6);
		// DLL.addIndex("8", 7);
		// DLL.addIndex("9", 3);
		// DLL.addIndex("10", 9);

		for (int i = 0; i < 15; i++) {
			// System.out.println("-------------------------");
			// System.out.println("First: " + DLL.peekFirst());
			// System.out.println("Last: " + DLL.peekLast());
			// System.out.println("Current: " + DLL.peekCurrent());
			// System.out.println("Index: " + DLL.peekIndex(i));
			// DLL.next();
			// DLL.prev();
			// DLL.setCurrent(i);
			// System.out.println("Size: " + DLL.getSize());
			// System.out.println("isEmpty: " + DLL.isEmpty());
			// System.out.println("removeFirst: " + DLL.removeFirst());
			// System.out.println("removeLast: " + DLL.removeLast());
			// System.out.println("removeCurrent: "+ DLL.removeCurrent());
			// System.out.println("removeIndex: "+ DLL.removeIndex(3));
		}
	}
}
